#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

use clap_args::arg;
mod proxy;
mod resp;
use std::{env, process::exit};

use cidr::Ipv6Cidr;
pub use resp::resp;
mod srv;

#[tokio::main]
async fn main() {
  log_init::init();

  if let Some(matches) = clap_args::parse!(|cmd| {
    cmd
      .arg(arg!(-b --bind [BIND] "http proxy bind address").default_value("0.0.0.0:7812"))
      .arg(
        arg!(-i --"ipv6_subnet" [IPv6_SUBNET] "ipv6 subnet , for example 1001:10f0:6001:48e4::/64")
          .required(true),
      )
  }) {
    let bind_addr = matches.get_one::<String>("bind").unwrap();
    let ipve_subnet = matches.get_one::<String>("ipv6_subnet").unwrap();

    log::info!(
      "{} v{} proxy {} subnet {}",
      env!("CARGO_PKG_NAME"),
      env!("CARGO_PKG_VERSION"),
      bind_addr,
      ipve_subnet
    );
    run(bind_addr, ipve_subnet).await
  }
}

async fn run(bind_addr: impl AsRef<str>, ipv6_subnet: impl AsRef<str>) {
  let ipv6 = match ipv6_subnet.as_ref().parse::<Ipv6Cidr>() {
    Ok(cidr) => {
      let a = cidr.first_address();
      let b = cidr.network_length();
      (a, b)
    }
    Err(_) => {
      log::error!("invalid ipv6 subnet");
      exit(1);
    }
  };

  let bind_addr = match bind_addr.as_ref().parse() {
    Ok(b) => b,
    Err(e) => {
      log::error!("bind address not valid: {}", e);
      return;
    }
  };

  xerr::log!(srv::srv(bind_addr, ipv6).await);
}
